#ifndef _NEXT_BATCH_HPP
#define _NEXT_BATCH_HPP 1

#include <stdint.h>
#include <iostream>
#include <boost/shared_ptr.hpp>
#include "../Parameters.hpp"
#include "MacArrayMessage.hpp"
#include "HistoryDigest.hpp"
#include "NonDeterminism.hpp"
#include "CommandBatch.hpp"
#include "CertificateEntry.hpp"

namespace BFT
{
	namespace messages
	{
		class NextBatch : public MacArrayMessage
		{
			public:
			
			NextBatch(uint16_t _tag, uint32_t view, boost::shared_ptr<NextBatch> _nb);
			
			NextBatch(uint16_t _tag, uint32_t view, uint32_t _seq, boost::shared_ptr<HistoryDigest> _hist,
				  boost::shared_ptr<CommandBatch> _batch, boost::shared_ptr<NonDeterminism> _non,
				  boost::shared_ptr<Digest> _cph, bool _cp, uint32_t _sendingReplica);
				  
			NextBatch(uint16_t _tag, uint32_t _view, uint32_t _seq, 
				  boost::shared_ptr<CertificateEntry> _entry, bool _cp, uint32_t _sendingReplica);
				  
			NextBatch(boost::shared_ptr<char> _bytes, int _bytes_size);
			
			boost::shared_ptr<HistoryDigest> getHistory();
			boost::shared_ptr<CommandBatch> getCommands();
			boost::shared_ptr<NonDeterminism> getNonDeterminism();
			boost::shared_ptr<CertificateEntry> getCertificateEntry();
			boost::shared_ptr<Digest> getCPDigest();
			
			bool matches(boost::shared_ptr<NextBatch> _nb);
			bool equals(boost::shared_ptr<NextBatch> _nb);
			
			bool getTakeCP();
			
			uint32_t getView();
			uint32_t getSeqNo();
			uint32_t getSendingReplica();
			
			void printInfo();
			
			protected:
			
			NextBatch(); //dummy constructor called only by subclassess before calling the real constructor
			
			uint32_t viewNo;
			uint32_t seqNo;
			
			boost::shared_ptr<CertificateEntry> certEntry;
			
			bool takeCP;
			
			private:
			
			static int computeSize(uint32_t _view, uint32_t _seq, 
					   boost::shared_ptr<CertificateEntry> _entry, bool _cp);
		};
		
		inline uint32_t NextBatch::getView() {return viewNo;}
		inline uint32_t NextBatch::getSeqNo() {return seqNo;}
		inline boost::shared_ptr<HistoryDigest> NextBatch::getHistory() {return certEntry.get()->getHistoryDigest();}
		inline boost::shared_ptr<CommandBatch> NextBatch::getCommands() {return certEntry.get()->getCommandBatch();}	
		inline boost::shared_ptr<NonDeterminism> NextBatch::getNonDeterminism() {return certEntry.get()->getNonDeterminism();}
		inline boost::shared_ptr<Digest> NextBatch::getCPDigest() {return certEntry.get()->getCPHash();}
		inline boost::shared_ptr<CertificateEntry> NextBatch::getCertificateEntry() {return certEntry;}	
		inline bool NextBatch::getTakeCP(){return takeCP;}
		inline uint32_t NextBatch::getSendingReplica() {return getSender();}
	}
}

#endif
